﻿#region  文件信息

// ---------------------------------------------------------------------------------------
// <copyright file="Class1.cs" company="">
// 作者：李帅伦
// </copyright>
// <summary>
// 类型简介：
// 类型详细：Class1.cs
// 创建时间：2015-01-12 17:05
// 修改时间：2015-01-12 11:17
// </summary>
// ---------------------------------------------------------------------------------------
#endregion

namespace Payment.Albaba.WapCode
{
    #region

    using System;
    using System.Collections.Generic;
    using System.Collections.Specialized;
    using System.Web;
    using System.Xml;

    using Newtonsoft.Json;

    using Payment.Albaba.Com;

    using WebCommon;

    #endregion

    /// <summary>
    /// The ali notify.
    /// </summary>
    public class AliWapNotify
    {
        #region Fields

        /// <summary>
        /// config
        /// </summary>
        private readonly AliConfig config;

        /// <summary>
        /// request
        /// </summary>
        private NameValueCollection coll;

        private AliWapNotifyModel model;

        #endregion

        #region Constructors and Destructors

        /// <summary>
        /// 构造函数
        ///     从配置文件中初始化变量
        /// </summary>
        /// <param name="config">
        /// The config.
        /// </param>
        /// <param name="model"></param>
        public AliWapNotify(AliConfig config, AliWapNotifyModel model)
        {
            this.config = config;
            this.model = model;
            this.model.GetnonotifyDataXml();
        }

        /// <summary>
        /// request数据
        /// </summary>
        /// <returns></returns>
        public string GetJson()
        {
            return JsonConvert.SerializeObject(this.coll);
        }
        #endregion

        #region Public Methods and Operators

        /// <summary>
        /// 解密
        /// </summary>
        /// <param name="inputPara">
        /// 要解密数据
        /// </param>
        /// <returns>
        /// 解密后结果
        /// </returns>
        public Dictionary<string, string> Decrypt(Dictionary<string, string> inputPara)
        {
            try
            {
                inputPara["notify_data"] = RsaFromPkcs8.decryptData(
                    inputPara["notify_data"],
                    this.config.Key,
                    this.config.SignType);
            }
            catch (Exception e)
            {
            }

            return inputPara;
        }

        /// <summary>
        /// 获取待签名字符串（调试用）
        /// </summary>
        /// <param name="inputPara">
        /// 通知返回参数数组
        /// </param>
        /// <returns>
        /// 待签名字符串
        /// </returns>
        public string GetPreSignStr(Dictionary<string, string> inputPara)
        {
            Dictionary<string, string> sPara = new Dictionary<string, string>();

            // 过滤空值、sign与sign_type参数
            sPara = AliCore.FilterPara(inputPara);

            // 获取待签名字符串
            string preSignStr = AliCore.CreateLinkString(sPara);

            return preSignStr;
        }

        /// <summary>
        /// 验证消息是否是支付宝发出的合法消息，验证服务器异步通知
        /// </summary>
        /// <param name="inputPara">
        /// 通知返回参数数组
        /// </param>
        /// <param name="sign">
        /// 支付宝生成的签名结果
        /// </param>
        /// <returns>
        /// 验证结果
        /// </returns>
        public bool VerifyNotify(Dictionary<string, string> inputPara, string sign)
        {
            // 解密
            if (this.config.SignType == "0001")
            {
                inputPara = this.Decrypt(inputPara);
            }

            // 获取是否是支付宝服务器发来的请求的验证结果
            string responseTxt = "true";
            try
            {
                // XML解析notify_data数据，获取notify_id
                string notify_id = string.Empty;
                XmlDocument xmlDoc = new XmlDocument();
                xmlDoc.LoadXml(inputPara["notify_data"]);
                notify_id = xmlDoc.SelectSingleNode("/notify/notify_id").InnerText;

                if (notify_id != string.Empty)
                {
                    responseTxt = this.GetResponseTxt(notify_id);
                }
            }
            catch (Exception e)
            {
                responseTxt = e.ToString();
            }

            // 获取返回时的签名验证结果
            bool isSign = this.GetSignVeryfy(inputPara, sign, false);

            // 写日志记录（若要调试，请取消下面两行注释）
            // string sWord = "responseTxt=" + responseTxt + "\n isSign=" + isSign.ToString() + "\n 返回回来的参数：" + GetPreSignStr(inputPara) + "\n ";
            // Core.LogResult(sWord);

            // 判断responsetTxt是否为true，isSign是否为true
            // responsetTxt的结果不是true，与服务器设置问题、合作身份者ID、notify_id一分钟失效有关
            // isSign不是true，与安全校验码、请求时的参数格式（如：带自定义参数等）、编码格式有关
            if (responseTxt == "true" && isSign)
            {
                // 验证成功
                return true;
            }

            return false;
        }

        /// <summary>
        /// 验证消息是否是支付宝发出的合法消息，验证callback
        /// </summary>
        /// <param name="inputPara">
        /// 通知返回参数数组
        /// </param>
        /// <param name="sign">
        /// 支付宝生成的签名结果
        /// </param>
        /// <returns>
        /// 验证结果
        /// </returns>
        public bool VerifyReturn(Dictionary<string, string> inputPara, string sign)
        {
            // 获取返回时的签名验证结果
            bool isSign = this.GetSignVeryfy(inputPara, sign, true);

            // 写日志记录（若要调试，请取消下面两行注释）
            // string sWord = "isSign=" + isSign.ToString() + "\n 返回回来的参数：" + GetPreSignStr(inputPara) + "\n ";
            // Core.LogResult(sWord);

            // 判断isSign是否为true
            // isSign不是true，与安全校验码、请求时的参数格式（如：带自定义参数等）、编码格式有关
            if (isSign)
            {
                // 验证成功
                return true;
            }

            return false;
        }

        #endregion

        #region Methods

        /// <summary>
        /// The get request post.
        /// </summary>
        /// <returns>
        /// The <see cref="Dictionary"/>.
        /// </returns>
        private Dictionary<string, string> GetRequestPost()
        {
            int i = 0;
            Dictionary<string, string> sArray = new Dictionary<string, string>();

            // Get names of all forms into a string array.
            string[] requestItem = this.coll.AllKeys;

            for (i = 0; i < requestItem.Length; i++)
            {
                sArray.Add(requestItem[i], this.coll[requestItem[i]]);
            }

            return sArray;
        }

        /// <summary>
        /// 获取是否是支付宝服务器发来的请求的验证结果
        /// </summary>
        /// <param name="notify_id">
        /// 通知验证ID
        /// </param>
        /// <returns>
        /// 验证结果
        /// </returns>
        private string GetResponseTxt(string notify_id)
        {
            string veryfy_url = AliGateway.WapHttpsVeryfyUrl + "partner=" + this.config.Partner + "&notify_id=" + notify_id;

            // 获取远程服务器ATN结果，验证是否是支付宝服务器发来的请求
            string responseTxt = this.Get_Http(veryfy_url, 120000);

            return responseTxt;
        }

        /// <summary>
        /// 获取返回时的签名验证结果
        /// </summary>
        /// <param name="inputPara">
        /// 通知返回参数数组
        /// </param>
        /// <param name="sign">
        /// 对比的签名结果
        /// </param>
        /// <param name="isSort">
        /// 是否对待签名数组排序
        /// </param>
        /// <returns>
        /// 签名验证结果
        /// </returns>
        private bool GetSignVeryfy(Dictionary<string, string> inputPara, string sign, bool isSort)
        {
            Dictionary<string, string> sPara = new Dictionary<string, string>();

            // 过滤空值、sign与sign_type参数
            if (isSort)
            {
                // 根据字母a到z的顺序把参数排序
                sPara = AliCore.FilterPara(inputPara);
            }
            else
            {
                sPara = this.SortNotifyPara(sPara);
            }

            // 获取待签名字符串
            string preSignStr = AliCore.CreateLinkString(sPara);

            // 获得签名验证结果
            bool isSgin = false;
            if (sign != null && sign != string.Empty)
            {
                isSgin = AliCore.Verify(preSignStr, sign, this.config.Key, this.config.InputCharset);
            }

            return isSgin;
        }

        /// <summary>
        /// 获取远程服务器ATN结果
        /// </summary>
        /// <param name="strUrl">
        /// 指定URL路径地址
        /// </param>
        /// <param name="timeout">
        /// 超时时间设置
        /// </param>
        /// <returns>
        /// 服务器ATN结果
        /// </returns>
        private string Get_Http(string strUrl, int timeout)
        {
            var httpHelper = new HttpHelper();
            httpHelper.Url = strUrl;
            httpHelper.Method = false;
            string strResult = httpHelper.PostPage();
            return strResult;
        }

        /// <summary>
        /// 异步通知时，对参数做固定排序
        /// </summary>
        /// <param name="dicArrayPre">
        /// 排序前的参数组
        /// </param>
        /// <returns>
        /// 排序后的参数组
        /// </returns>
        private Dictionary<string, string> SortNotifyPara(Dictionary<string, string> dicArrayPre)
        {
            Dictionary<string, string> sPara = new Dictionary<string, string>();
            sPara.Add("service", dicArrayPre["service"]);
            sPara.Add("v", dicArrayPre["v"]);
            sPara.Add("sec_id", dicArrayPre["sec_id"]);
            sPara.Add("notify_data", dicArrayPre["notify_data"]);

            return sPara;
        }

        #endregion
    }
}